import _ from 'lodash';
import utils from '../../utils';
import page from '../../apis/page';
import { observable, action, toJS } from 'mobx';
import { ruleTypes } from '../../constants/form';
import { isOptional, isNormal } from '../../components/designer/form/component/typeof';

const { FIELD, JUMP } = ruleTypes;

export default class EdcFormRuleStore {
  @observable hasInit = '';
  @observable appid = '';
  @observable coms = [];
  @observable type = FIELD;
  @observable triggers = []; // 可触发规则的组件
  @observable targets = []; // 可用于被触发规则的组件
  @observable rules = [];
  @observable selectedIds = {
    [FIELD]: '',
    [JUMP]: ''
  };

  @action init(appid) {
    this.appid = appid;
    this.hasInit = false;

    Promise.all([
      page.getDesign(appid),
      page.getPageRules(appid)
    ]).then(([{ main: coms }, rules]) => {
      this.hasInit = true;
      this.initDatas(coms, rules);
    });
  }

  @action onTypeChange = type => {
    this.type = type;
  }

  @action onRulesChange = rule => {
    if(_.isArray(rule)) {
      this.rules = [...rule];
    } else {
      this.rules = toJS(this.rules).map(r => {
        if(rule.id === r.id) return toJS(rule);

        return r;
      });
    }
  }

  @action isValid = rule => {
    const { trigger, option, target, type } = rule;
    const hasSelect = trigger.id && option.key;

    if (!hasSelect) return false;
    if (JUMP === type) return utils.isUrl(target);

    return target.length;
  }

  @action addNewRule = () => {
    const rules = toJS(this.rules);
    const newRule = {
      id: utils.UUID(),
      type: this.type,
      target: FIELD === this.type ? [] : '',
      trigger: {
        name: '',
        id: ''
      },
      option: {
        showname: '',
        key: ''
      }
    };

    rules.push(newRule);

    this.rules = rules;
    this.selectedIds[this.type] = newRule.id;
  }

  @action onRuleDelete = (rId) => {
    const index = this.rules.findIndex(r => rId === r.id);

    this.rules.splice(index, 1);

    if(rId === this.selectedIds[this.type]) {
      this.selectedIds[this.type] = '';
    }
  }

  @action onRuleChange = (newRule) => {
    const { type, selectedIds, rules } = this;
    const selectedId = selectedIds[type];
    const rule = rules.find(r => selectedId === r.id);

    Object.assign(rule, newRule);

    this.rules = toJS(rules);
  }

  @action onSelectedIdChange = selectedId => {
    this.selectedIds[this.type] = selectedId;
    this.selectedIds = toJS(this.selectedIds);
  }

  @action initState() {
    this.coms = [];
    this.type = FIELD;
    this.triggers = [];
    this.targets = [];
    this.rules = [];
    this.selectedIds = {};
  }

  @action onSave = () => {
    const rules = this.getRules();

    return page.updatePageRules(this.appid, JSON.stringify(rules));
  }

  getRules() {
    const validRules = toJS(this.rules).filter(this.isValid);

    return validRules.map(({ id, option, trigger, target, type }) => {
      let _target = target;

      if(_.isArray(target)) {
        _target = target.map(({ id }) => id).join(',');
      }

      return {
        type,
        uuid: id,
        target: _target,
        option: option.key,
        trigger: trigger.id
      };
    });
  }

  initDatas(coms, rules) {
    const optionalComs = coms.filter(isOptional);

    this.coms = coms;
    this.targets = coms.filter(isNormal).map(com => ({
      id: com.uuid,
      name: com.config.title
    }));
    this.triggers = optionalComs.map(com => {
      return {
        id: com.uuid,
        name: com.config.title,
        options: com.config.options
      };
    });
    this.rules = this.parseRules(rules);
  }

  parseRules(rules) {
    return rules.map(({ uuid, option, target, trigger, type }) => {
      const {
        uuid: tId, 
        config: { options, title } 
      } = this.getComponent(trigger);
      
      target = this.parseTarget(target, type);
      option = options.find(opt => option === opt.key);

      return {
        id: uuid,
        type,
        option,
        target,
        trigger: {
          options,
          id: tId,
          name: title
        }
      };
    });
  }

  parseTarget(target, type) {
    if (JUMP === type) return target;

    return target.split(',').map(tId => {
      const { config: { title } } = this.getComponent(tId);

      return {
        id: tId,
        name: title
      };
    });
  }

  getComponent(uuid) {
    return this.coms.find(com => uuid === com.uuid);
  }
}